package org.jet.emall.rbac;

import org.jet.emall.rbac.annotation.ApiInformation;
import org.jet.emall.rbac.dto.AdminMenuDTO;
import org.jet.emall.rbac.dto.AdminOperationDTO;
import org.jet.emall.rbac.service.CustomAdminMenuService;
import org.jet.emall.rbac.service.CustomAdminOperationService;
import org.jet.emall.security.comp.DynamicPrivilegeManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * ApplicationRunnerImpl 实现了ApplicationRunner接口，其run方法会在springboot程序启动初始化容器中的所有bean之后回调
 * 在这里用来做操作权限相关表的数据初始化工作
 * @author xiaozai
 * @version 1.0
 * @date 2020-04-09 14:42
 */
@Component
public class ApplicationRunnerImpl implements ApplicationRunner {

    @Autowired
    private CustomAdminMenuService customAdminMenuService;

    @Autowired
    private WebApplicationContext applicationContext;
    @Autowired
    private CustomAdminOperationService customAdminOperationService;

    @Autowired
    private DynamicPrivilegeManager dynamicPrivilegeManager;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //初始化tb_admin_operation表
        if(!isApiInformationInitialize()){
            initApiInformation();
        }

        //加载运态权限数据到内存中
        dynamicPrivilegeManager.refresh();
    }

    private boolean isApiInformationInitialize(){
        return customAdminOperationService.count()>0;
    }

    /**
     * 初始化 操作相关表
     */
    private void initApiInformation() {

        int codeBase = 101;
        RequestMappingHandlerMapping mapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
        // 获取url与类和方法的对应信息
        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();

        List<AdminOperationDTO> list = new ArrayList<>();

        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet()) {
            RequestMappingInfo key = m.getKey();
            HandlerMethod value = m.getValue();

            Method method = value.getMethod();
            //获取控制器方法上的ApiInformation注解
            ApiInformation apiOperation = method.getAnnotation(ApiInformation.class);
            if (apiOperation == null) {
                continue;
            }

            RequestMapping requestMappingAnnotation = method.getAnnotation(RequestMapping.class);
            String url = requestMappingAnnotation.value()[0];
            String requestMethodName = requestMappingAnnotation.method()[0].toString().toLowerCase();
            AdminOperationDTO dto = new AdminOperationDTO();
            dto.setUrl(url);
            dto.setMethod(requestMethodName);
            dto.setName(apiOperation.function());
            dto.setCode("" + codeBase++);
            if (!apiOperation.menu().isEmpty()) {
                AdminMenuDTO adminMenuDTO = customAdminMenuService.getMenuByName(apiOperation.menu().trim());
                dto.setMenuId(adminMenuDTO.getId());
            }
            list.add(dto);
        }
        //保存所有api
        customAdminOperationService.save(list);
        //将所有api赋给所有角色
        customAdminOperationService.assignAllPrivilegesToEveryRole();
    }
}
